// 收集各个子组件的数据
// 父组件通过 props 传入收集函数，但是调用时机不由子组件掌控，父组件自己决定何时调用，比如在准备最终提交的时候调用
// 子组件通过 useImperativeHandle 暴露收集函数，参数传入自己当前采集到配置
// 父组件通过参数给每个子组件一个定位函数
// 子组件在定位好的位置上写自己的数据
// 场景1：大型配置
// 从上向下传递配置数据slice，子组件收到原版编辑，否则按默认配置开始编辑
// 完了子组件自己点保存，过程中遮罩子组件，保存成功后更新父组件状态，props 新版重新流入
// 场景2：大型业务表单
// 从上向下传递配置数据slice，子组件收到原版编辑，否则按默认配置开始编辑
// 子组件编辑完，点锁定或确定，然后通过调用回调写回父组件 props.report(selfState)
// 父组件最终业务提交时，检查全部数据；也可以通过子组件的 ref.current.check 分派下检查

import React, { useRef, useImperativeHandle, useCallback, useState } from 'react';
import produce from 'immer';

const Component = React.forwardRef((props: any, ref: any) => {

  const [state, setState] = useState<number>(Number(props.id));

  // 向上暴露子组件数据和方法
  useImperativeHandle(ref, () => {

    // console.log(1, ref);
    // ref.current = state; // 经测试，直接修改 ref.current 无效，必须返回想看设置到 current 中的内容
    // console.log(2, ref);

    // ref.current[props.id] = state; // object is not extensible
    // return ref.current;

    console.log('in useImperativeHandle', ref);
    // 这里面当 state 改变后，ref.current 会变成 null，失去了原来的状态
    return produce(ref.current || {}, (draft: any) => {
      draft[props.id] = state;
    });
  }, [state]);

  return (
    <div>
      <input value={state} type="number" onChange={(e) => setState(Number(e.target.value))} />
      <button onClick={() => setState(v => v + 1)}>增加</button>
    </div>
  );
});

export default function CollectChildConfig() {
  const ref = useRef<any>({});
  const handleButtonClick = useCallback(() => {
    console.log(ref);
  }, []);
  console.log('ref.current', ref.current);
  return (
    <div>
      <div><button onClick={handleButtonClick}>focus component below</button></div>
      <Component ref={ref} id="1" />
      <Component ref={ref} id="2" />
    </div>
  );
}
